﻿using System;
using System.Collections.Generic;
using System.Linq;

using SharedGenomics.Core;
using SharedGenomics.Domain;
using SharedGenomics.Annotations;

namespace SharedGenomics.Workbench.Annotations
{
    public class ResultSetAnnotator : IAnalysisResultSetAnnotator
    {
        private readonly SnpAnnotationRepositoryFactory _annotationSetFactory;
        private readonly IAnnotationPlanFactory _planFactory;
        private readonly AnnotationPlanRunnerFactory _planRunnerFactory;
        private readonly IAnnotationRequestStatusNotifier _statusNotifier;
        private readonly IAnnotationRepositoryMediator _annotations;

        private IList<AnnotationPlanRunner> _planRunners;           //list to store all current plan runners to stop them being garbage collected

        public ResultSetAnnotator(SnpAnnotationRepositoryFactory annotationRepositoryFactory, IAnnotationPlanFactory planFactory, AnnotationPlanRunnerFactory planRunnerFactory, IAnnotationRequestStatusNotifier requestNotifier, IAnnotationRepositoryMediator annotations)
        {
            this._annotationSetFactory = annotationRepositoryFactory;
            this._planFactory = planFactory;
            this._planRunnerFactory = planRunnerFactory;
            this._statusNotifier = requestNotifier;
            this._annotations = annotations;

            this._planRunners = new List<AnnotationPlanRunner>();
        }

        public SnpAnnotationRepository Annotate(IAnalysisResultSet resultSet)
        {
            resultSet.ThrowIfNull("resultSet");

            //create annotation sets for results
            var annotations = this._annotationSetFactory.CreateFor(resultSet);

            //TODO: stop all running plans and the request pipeline!
            //create annotation plans and plan runners
            this._planRunners = annotations.AnnotationSets.Select(set => this._planRunnerFactory.CreatePlanRunner(set)).ToList();

            //associate plan runners with the notifier
            this._statusNotifier.ClearNotifications();
            this._planRunners.ForEach(runner => this._statusNotifier.AddNotificationFor(runner));

            //add all snp names into annotation repository
            var resultSetSnps = resultSet.OfType<AnalysisResult>().SelectMany(result => result.GetSnpPropertyValues()).Distinct(StringComparer.InvariantCultureIgnoreCase);

            resultSetSnps.ForEach(snp => this._annotations.Add(AnnotationKey.SnpName, snp, null));

            //execute all plans
            this._planRunners.ForEach(runner => runner.Run(this._planFactory.CreatePlan()));

            return annotations;
        }
    }
}
